package com.jichangxiu.server.platform.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jichangxiu.common.constant.Constant;
import com.jichangxiu.common.entity.bo.PageData;
import com.jichangxiu.common.exception.ServiceException;
import com.jichangxiu.common.properties.JcxProperties;
import com.jichangxiu.common.utils.StrUtils;
import com.jichangxiu.framework.mybatis.BaseServiceImpl;
import com.jichangxiu.server.platform.entity.dto.PlatformTenantQueryDto;
import com.jichangxiu.server.platform.entity.map.*;
import com.jichangxiu.server.platform.entity.po.*;
import com.jichangxiu.server.platform.entity.vo.*;
import com.jichangxiu.server.platform.mapper.PlatformTenantMapper;
import com.jichangxiu.server.platform.service.*;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.validation.constraints.NotBlank;
import java.util.ArrayList;
import java.util.List;

/**
 * PlatformTenantServiceImpl:
 *
 * @author Jcx
 * @create 2023-03-08 21:18
 */
@Service
public class PlatformTenantServiceImpl extends BaseServiceImpl<PlatformTenantMapper, PlatformTenant> implements PlatformTenantService {

    @Resource
    private StrUtils strUtils;

    @Resource
    private JcxProperties jcxProperties;

    @Resource
    private PlatformTenantMapper platformTenantMapper;

    @Resource
    private PlatformDeptService platformDeptService;

    @Resource
    private PlatformPostService platformPostService;

    @Resource
    private PlatformRoleService platformRoleService;

    @Resource
    private PlatformUserService platformUserService;

    @Resource
    private PlatformConfigService platformConfigService;

    @Resource
    private PlatformUserRoleService platformUserRoleService;

    @Resource
    private PlatformUserPostService platformUserPostService;

    /**
     * 新增租户
     *
     * @param platformTenantAddVo 租户视图对象
     * @return 是否成功
     */
    @Override
    public Boolean add(PlatformTenantAddVo platformTenantAddVo) {
        if (ObjectUtil.isEmpty(platformTenantAddVo)) {
            throw ServiceException.build("租户对象无效");
        }

        PlatformTenant platformTenant = PlatformTenantBasic.INSTANCE.toPlatformTenant(platformTenantAddVo);
        if (ObjectUtil.isEmpty(platformTenant)) {
            throw ServiceException.build("租户对象无效");
        }

        if (!Validator.isEmail(platformTenant.getEmail())) {
            throw ServiceException.build("租户联系邮箱不符合规范");
        }

        if (!Validator.isMobile(platformTenant.getPhone())) {
            throw ServiceException.build("租户联系电话不符合规范");
        }

        if (Constant.PLATFORM_SUPER_TENANT.equals(platformTenant.getTenantCode())) {
            throw ServiceException.build("租户标识不能为 PLATFORM_SUPER_TENANT");
        }

        // Code 必须唯一
        PlatformTenant dbPlatformTenantByCode = getOne(new LambdaQueryWrapper<PlatformTenant>().eq(PlatformTenant::getTenantCode, platformTenant.getTenantCode()));
        if (ObjectUtil.isNotEmpty(dbPlatformTenantByCode)) {
            throw ServiceException.build(platformTenant.getTenantName() + "该租户的标识重复");
        }

        // name 必须唯一
        PlatformTenant dbPlatformTenantByName = getOne(new LambdaQueryWrapper<PlatformTenant>().eq(PlatformTenant::getTenantName, platformTenant.getTenantName()));
        if (ObjectUtil.isNotEmpty(dbPlatformTenantByName)) {
            throw ServiceException.build(platformTenant.getTenantName() + "该租户的名称重复");
        }

        String tenantId = IdWorker.get32UUID();

        platformTenant.setTenantNo(strUtils.createNo("tenant"));
        platformTenant.setIsPlatform(false);
        platformTenant.setTenantId(tenantId);

        String adminDeptId = IdWorker.get32UUID();
        String adminPostId = IdWorker.get32UUID();
        String adminUserId = IdWorker.get32UUID();
        String adminRoleId = IdWorker.get32UUID();

        // 部门
        PlatformDeptAddVo platformDeptAddVo = new PlatformDeptAddVo(Constant.SYSTEM_SUPER_DEPT, platformTenant.getTenantName(), "0", adminUserId, platformTenant.getPhone(), platformTenant.getEmail(), 1, platformTenant.getTenantName(), true);
        PlatformDept platformDept = PlatformDeptBasic.INSTANCE.toPlatformDept(platformDeptAddVo);
        platformDept.setDeptId(adminDeptId);
        platformDept.setDeptNo(strUtils.createNo("dept"));
        platformDept.setTenantId(tenantId);

        // 岗位
        PlatformPostAddVo platformPostAddVo = new PlatformPostAddVo(Constant.SYSTEM_SUPER_POST, platformTenant.getTenantName() + "_超管", platformTenant.getTenantName() + "_超管", adminDeptId, true);
        PlatformPost platformPost = PlatformPostBasic.INSTANCE.toPlatformPost(platformPostAddVo);
        platformPost.setPostId(adminPostId);
        platformPost.setPostNo(strUtils.createNo("post"));
        platformPost.setTenantId(tenantId);
        List<String> postIds = new ArrayList<>();
        postIds.add(platformPost.getPostId());

        // 角色
        PlatformRoleAddVo platformRoleAddVo = new PlatformRoleAddVo(Constant.SYSTEM_SUPER_ROLE, platformTenant.getTenantName() + "_超级管理员", platformTenant.getTenantName() + "_租户超级管理员", true, 1.0);
        PlatformRole platformRole = PlatformRoleBasic.INSTANCE.toPlatformRole(platformRoleAddVo);
        platformRole.setRoleId(adminRoleId);
        platformRole.setRoleNo(strUtils.createNo("role"));
        platformRole.setTenantId(tenantId);
        List<String> roleIds = new ArrayList<>();
        roleIds.add(platformRole.getRoleId());

        String initPassword = platformConfigService.getPlatformConfigValue("INIT_PASSWORD", "INIT_PASSWORD", jcxProperties.getAuthProperties().getInitPassword());

        // 用户
        PlatformUserAddVo platformUserAddVo = new PlatformUserAddVo(Constant.SYSTEM_SUPER_USER, "admin", new BCryptPasswordEncoder().encode(initPassword), adminDeptId, platformTenant.getTenantName() + "_超管", platformTenant.getPhone(), platformTenant.getEmail(), 2L, platformTenant.getLogoUrl(), true, platformTenant.getTenantName() + "_超管", roleIds, postIds);
        PlatformUser platformUser = PlatformUserBasic.INSTANCE.toPlatformUser(platformUserAddVo);
        platformUser.setUserId(adminUserId);
        platformUser.setUserNo(strUtils.createNo("user"));
        platformUser.setTenantId(tenantId);

        // 用户角色关联关系
        List<PlatformUserRole> platformUserRoleList = new ArrayList<>();
        roleIds.forEach(roleId -> {
            platformUserRoleList.add(PlatformUserRole.builder().userId(platformUser.getUserId()).roleId(roleId).tenantId(tenantId).build());
        });

        // 用户岗位关联关系
        List<PlatformUserPost> platformUserPostList = new ArrayList<>();
        postIds.forEach(postId -> {
            platformUserPostList.add(PlatformUserPost.builder().userId(platformUser.getUserId()).postId(postId).tenantId(tenantId).build());
        });

        boolean b1 = save(platformTenant);
        boolean b2 = platformDeptService.save(platformDept);
        boolean b3 = platformPostService.save(platformPost);
        boolean b4 = platformRoleService.save(platformRole);
        boolean b5 = platformUserService.save(platformUser);
        boolean b6 = platformUserRoleService.saveBatch(platformUserRoleList);
        boolean b7 = platformUserPostService.saveBatch(platformUserPostList);
        return b1 && b2 && b3 && b4 && b5 && b6 && b7;
    }

    /**
     * 多选级联删除租户
     *
     * @param tenantIdList 租户ID列表
     * @return 是否成功
     */
    @Override
    public Boolean del(List<String> tenantIdList) {
        List<PlatformTenant> platformTenantList = list(new LambdaQueryWrapper<PlatformTenant>().in(PlatformTenant::getTenantId, tenantIdList));
        if (ObjectUtil.isEmpty(platformTenantList)) {
            throw ServiceException.build("数据库中不存在需要删除的记录");
        }
        platformTenantList.forEach(platformTenant -> {
            if (Constant.PLATFORM_SUPER_TENANT.equals(platformTenant.getTenantCode())) {
                throw ServiceException.build("标识为 PLATFORM_SUPER_TENANT 的租户不能删除");
            }
        });
        // 删除岗位
        return platformTenantMapper.deletePlatformTenantByIds(tenantIdList) > 0;
    }

    /**
     * 修改租户信息
     *
     * @param platformTenantEditVo 租户视图对象
     * @return 是否成功
     */
    @Override
    public Boolean edit(PlatformTenantEditVo platformTenantEditVo) {
        if (ObjectUtil.isEmpty(platformTenantEditVo)) {
            throw ServiceException.build("租户对象无效");
        }

        PlatformTenant platformTenant = PlatformTenantBasic.INSTANCE.toPlatformTenant(platformTenantEditVo);
        if (ObjectUtil.isEmpty(platformTenant)) {
            throw ServiceException.build("租户对象无效");
        }

        PlatformTenant dbPlatformTenant = getOne(new LambdaQueryWrapper<PlatformTenant>().eq(PlatformTenant::getTenantId, platformTenant.getTenantId()));
        if (ObjectUtil.isEmpty(dbPlatformTenant)) {
            throw ServiceException.build(platformTenant.getTenantName() + "该租户在数据库中不存在");
        }

        if (!Validator.isEmail(platformTenant.getEmail())) {
            throw ServiceException.build("租户联系邮箱不符合规范");
        }

        if (!Validator.isMobile(platformTenant.getPhone())) {
            throw ServiceException.build("租户联系电话不符合规范");
        }

        if (Constant.PLATFORM_SUPER_TENANT.equals(dbPlatformTenant.getTenantCode()) && !dbPlatformTenant.getTenantCode().equals(platformTenant.getTenantCode())) {
            throw ServiceException.build("标识为 PLATFORM_SUPER_TENANT 的租户不能修改标识");
        }

        if (Constant.PLATFORM_SUPER_TENANT.equals(dbPlatformTenant.getTenantCode()) && !dbPlatformTenant.getStatus().equals(platformTenant.getStatus())) {
            throw ServiceException.build("标识为 PLATFORM_SUPER_TENANT 的租户不能修改状态");
        }

        // Code 必须唯一
        if (!platformTenant.getTenantCode().equals(dbPlatformTenant.getTenantCode())) {
            PlatformTenant dbPlatformTenantByCode = getOne(new LambdaQueryWrapper<PlatformTenant>().eq(PlatformTenant::getTenantCode, platformTenant.getTenantCode()));
            if (ObjectUtil.isNotEmpty(dbPlatformTenantByCode)) {
                throw ServiceException.build(platformTenant.getTenantName() + "该租户的标识重复");
            }
        }

        // name 必须唯一
        if (!platformTenant.getTenantName().equals(dbPlatformTenant.getTenantName())) {
            PlatformTenant dbPlatformTenantByName = getOne(new LambdaQueryWrapper<PlatformTenant>().eq(PlatformTenant::getTenantName, platformTenant.getTenantName()));
            if (ObjectUtil.isNotEmpty(dbPlatformTenantByName)) {
                throw ServiceException.build(platformTenant.getTenantName() + "该租户的名称重复");
            }
        }

        BeanUtil.copyProperties(platformTenant, dbPlatformTenant, true);
        return updateById(dbPlatformTenant);
    }

    /**
     * 根据ID获取租户详情
     *
     * @param tenantId 租户ID
     * @return 租户详情
     */
    @Override
    public PlatformTenantQueryDto info(@NotBlank(message = "租户ID不能为空") String tenantId) {
        PlatformTenant platformTenant = getOne(new LambdaQueryWrapper<PlatformTenant>().eq(PlatformTenant::getTenantId, tenantId));
        return PlatformTenantBasic.INSTANCE.toPlatformTenantQueryDto(platformTenant);
    }

    /**
     * 根据租户名称获取租户详情
     *
     * @param tenantName 租户名称
     * @return 租户详情
     */
    @Override
    public PlatformTenantQueryDto getTenantByTenantName(String tenantName) {
        PlatformTenant platformTenant = getOne(new LambdaQueryWrapper<PlatformTenant>().eq(PlatformTenant::getTenantName, tenantName));
        return PlatformTenantBasic.INSTANCE.toPlatformTenantQueryDto(platformTenant);
    }

    /**
     * 分页查询租户列表
     *
     * @param platformTenantQueryVo 租户视图对象
     * @return 分页租户列表
     */
    @Override
    public PageData<PlatformTenantQueryDto> pageList(PlatformTenantQueryVo platformTenantQueryVo) {
        Page<PlatformTenant> page = startPage();
        List<PlatformTenant> platformTenantList = platformTenantMapper.pageList(PlatformTenantBasic.INSTANCE.toPlatformTenant(platformTenantQueryVo), page);
        List<PlatformTenantQueryDto> platformTenantQueryDtos = PlatformTenantBasic.INSTANCE.toPlatformTenantQueryDtoList(platformTenantList);
        return PageData.build(new Page<>(page.getCurrent(), page.getSize(), page.getTotal()), platformTenantQueryDtos);
    }

}
